<?php
/**
 * Tags url model
 *
 * @category   Ddup
 * @package    Ddup_Tags
 * @author     Aaron
 */
class Ddup_Tags_Model_Url
{
    /**
     * Number of characters allowed to be in URL path
     *
     * @var int
     */
    const MAX_REQUEST_PATH_LENGTH = 240;

    /**
     * Number of characters allowed to be in URL path
     * after MAX_REQUEST_PATH_LENGTH number of characters
     *
     * @var int
     */
    const ALLOWED_REQUEST_PATH_OVERFLOW = 10;

	/**
     * Resource model
     *
     * @var Ddup_Tags_Model_Resource_Url
     */
    protected $_resourceModel;
    
    /**
     * Rewrite cache
     *
     * @var array
     */
    protected $_rewrites = array();
    
    /**
     * Current url rewrite rule
     *
     * @var Varien_Object
     */
    protected $_rewrite;
    
    /**
     * Retrieve stores array or store model
     *
     * @param int $storeId
     * @return Ddup_Core_Model_Store|array
     */
    public function getStores($storeId = null)
    {
        return $this->getResource()->getStores($storeId);
    }

    /**
     * Retrieve resource model
     *
     * @return Ddup_Tags_Model_Resource_Eav_Mysql4_Url
     */
    public function getResource()
    {
        if (is_null($this->_resourceModel)) {
            $this->_resourceModel = Mage::getResourceModel('tags/url');
        }
        return $this->_resourceModel;
    }
    
    /**
     * Refresh tags rewrite urls for some store or for all stores
     * 
     *
     * @param int $storeId
     * @return Ddup_Tags_Model_Url
     */
    public function refreshTagsRewrites($storeId = null)
    {
        if (is_null($storeId)) {
            foreach ($this->getStores() as $store) {
                $this->refreshTagsRewrites($store->getId());
            }
            return $this;
        }

        $this->clearStoreTagsInvalidRewrites($storeId);
        $tagCollection = $this->getResource()->getTagsByStore($storeId);
        $tagIds = $this->getResource()->getTagIds($storeId);
        $this->_rewrites = $this->getResource()->prepareTagsRewrites($storeId, $tagIds);
        
        foreach ($tagCollection as $tag) {
        	$this->_refreshTagRewrite($tag);
        }

        return $this;
    }
    
    /**
     * Refresh tag rewrite
     *
     * @param $tagId
     * @return Ddup_Tags_Model_Url
     */
    protected function _refreshTagRewrite($tag)
    {
    	$idPath      = $this->generateTagPath('id', $tag);
        $targetPath  = $this->generateTagPath('target', $tag);
    	$requestPath  = $this->generateTagPath('request', $tag);

        $rewriteData = array(
            'store_id'      => $tag->getStoreId(),
            'category_id'   => NULL,
            'product_id'    => NULL,
            'tag_id'    => $tag->getId(),
            'id_path'       => $idPath,
            'request_path'  => $requestPath,
            'target_path'   => $targetPath,
            'is_system'     => 0
        );
        
        $this->getResource()->saveRewrite($rewriteData, $this->_rewrite);
    	return $this;
    } 
    
	public function generateTagPath($type = 'target', $tag)
    {
        if (!$tag) {
            Mage::throwException(Mage::helper('core')->__('Please specify either a tag.'));
        }
        
        $urlPrefix = Mage::getStoreConfig('tags/settings/url_prefix');
        $urlSuffix = Mage::getStoreConfig('tags/settings/url_suffix');

        // generate id_path
        if ('id' === $type) {
            return 'tag/' . $tag->getId();
        }

        // generate request_path
        if ('request' === $type) {
        	$urlKey = Mage::getSingleton('catalog/category')->formatUrlKey($tag->getName());
        	return $this->getUnusedPath($tag->getStoreId(), $urlPrefix . $urlKey . $urlSuffix,
				$this->generateTagPath('id', $tag)
            );
        }
    
        // generate target_path
        return 'tag/product/list/tagId/' . $tag->getId();
    }
    
	/**
     * Get requestPath that was not used yet.
     *
     * Will try to get unique path by adding -1 -2 etc. between url_key and optional url_suffix
     *
     * @param int $storeId
     * @param string $requestPath
     * @param string $idPath
     * @return string
     */
    public function getUnusedPath($storeId, $requestPath, $idPath)
    {   
        $suffix = '.html';
        if (empty($requestPath)) {
            $requestPath = '-';
        } elseif ($requestPath == $suffix) {
            $requestPath = '-' . $suffix;
        }

        /**
         * Validate maximum length of request path
         */
        if (strlen($requestPath) > self::MAX_REQUEST_PATH_LENGTH + self::ALLOWED_REQUEST_PATH_OVERFLOW) {
            $requestPath = substr($requestPath, 0, self::MAX_REQUEST_PATH_LENGTH);
        }

        if (isset($this->_rewrites[$idPath])) {
            $this->_rewrite = $this->_rewrites[$idPath];
            if ($this->_rewrites[$idPath]->getRequestPath() == $requestPath) {
                return $requestPath;
            }
        }
        else {
            $this->_rewrite = null;
        }

        $rewrite = $this->getResource()->getTagRewriteByRequestPath($requestPath, $storeId);
        if ($rewrite && $rewrite->getId()) {
            if ($rewrite->getIdPath() == $idPath) {
                $this->_rewrite = $rewrite;
                return $requestPath;
            }
            // match request_url abcdef1234(-12)(.html) pattern
            $match = array();
            if (!preg_match('#^([0-9a-z/-]+?)(-([0-9]+))?('.preg_quote($suffix).')?$#i', $requestPath, $match)) {
                return $this->getUnusedPath($storeId, '-', $idPath);
            }
            $requestPath = $match[1].(isset($match[3])?'-'.($match[3]+1):'-1').(isset($match[4])?$match[4]:'');
            return $this->getUnusedPath($storeId, $requestPath, $idPath);
        }
        else {
            return $requestPath;
        }
    }
    
	/**
     * Deletes old rewrites for store, left from the times when store had some other root category
     *
     * @param int $storeId
     * @return Ddup_Catalog_Model_Url
     */
    public function clearStoreTagsInvalidRewrites($storeId = null)
    {
        if (is_null($storeId)) {
            foreach ($this->getStores() as $store) {
                $this->clearStoreTagsInvalidRewrites($store->getId());
            }
            return $this;
        }

        $this->getResource()->clearStoreTagsInvalidRewrites($storeId);
        return $this;
    }
}
